package
{
	import flare.data.DataField;
	import flare.data.DataSet;
	import flare.data.DataSource;
	import flare.query.methods.*;
	import flare.vis.data.Data;
	
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.utils.*;
	
	public class DataManager
	{
		
		private var fields:Array;
		private var data:Array;
		
		private var notifyTarget:Object;
		private var notifyFunction:Function;
		
		private var NUMBUCKETS:Number = 5;
		
		public function DataManager(target:Object, func:Function)
		{
			notifyTarget = target;
			notifyFunction = func;
			
			// connect to data source
			//http://www.stanford.edu/~dmac/cs448b/sample.tab
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/presidential-race-donations-from-win/versions/1.txt
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/presidential-race-donations-from-mas/versions/1.txt
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/fat-in-food/versions/1.txt
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/2008-election-primary-votes/versions/1.txt
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/okp-the-lesson-top-albums-of-2008/versions/1.txt
			//http://manyeyes.alphaworks.ibm.com/manyeyes/datasets/movies-by-continent-country-religion/versions/1.txt
			var ds:DataSource = new DataSource(
				"http://www.stanford.edu/~dmac/cs448b/donations.txt", "tab"
			);
			var loader:URLLoader = ds.load();
			loader.addEventListener(Event.COMPLETE, function(evt:Event):void
			{
				var ds:DataSet = loader.data as DataSet;
				data = Data.fromDataSet(ds).nodes.toDataArray();
				
				fields = new Array();
				for each (var df:DataField in ds.nodes.schema.fields) {
					fields.push(df.name);
				}
				
				bucketData();
				
				//query("gender", [{name:"race", value:"white"}]);
				if(notifyFunction != null && notifyTarget != null) {
					notifyFunction.call(notifyTarget);
				}

			});
		}
		
		public function getVariables():Array
		{
			if(data != null)
			{
				if(data.length > 0)
				{
					var datum:Object = data[0];
					var vars:Array = new Array();
					for(var prop:String in datum)
					{
						vars.push(prop);
					}
					
					return vars;
				}
			}
			
			return new Array("Gender", "Race", "Income", "Marital");
		}
		
		public function totalDatums():Number
		{
			var selectArr:Array = [{count:count("*")}];
			var r:Array = select.apply(null, selectArr).eval(data);
						  
			for each (var obj:Object in r) {
				return obj.count;
			}		
			
			return 0;
		}
		
		public function query(groupName:String, whereValues:Array):Array
		{
			var selectArr:Array = [groupName, {count:count("*")}];
			var r:Array;
			
			if (whereValues.length > 0)
			{
				var andArr:Array = new Array();
				for each (var obj:Object in whereValues) {
					andArr.push(eq(obj.name, _(obj.value)));
				}
			
				r = select.apply(null, selectArr)
						  .where(and.apply(null, andArr))
						  .groupby(groupName)
						  .orderby("-count")
						  .eval(data);
			} else {
				r = select.apply(null, selectArr)
						  .groupby(groupName)
						  .orderby("-count")
						  .eval(data);
			}
			
			//trace(resultToString(r));
			var initialResult:Array = resultToArray(r, groupName);
			var formattedResult:Array = new Array();
			
			for(var i:Number = 0; i < initialResult.length; i++)
			{
				var nameValue:Object = initialResult[i];
				formattedResult.push({name:groupName, value:nameValue.name, count:nameValue.value});
			}
			
			return formattedResult;
		}
		
		private function bucketData():void
		{
			for each (var field:String in fields) {
				var r:Array = select(field).eval(data);
				var num:Number = parseInt(r[0][field]);
				if (!isNaN(num)) {
					bucketAttribute(field);
				}
			}
		}
		
		private function bucketAttribute(field:String):void
		{
			var maxVal:Number = select({max:max(field)}).eval(data)[0].max;
			var minVal:Number = select({min:min(field)}).eval(data)[0].min;
			var step:Number = int((maxVal-minVal)/(NUMBUCKETS-1));
			
			for each (var obj:Object in data) {
				var value:Number = obj[field];
				var bucket:Number = int((value-.01)/step);
				var lower:Number = minVal+(bucket*step);
				var higher:Number = lower+step-1;
				obj[field] = lower + "-" + higher;
			}
			
			/*
			var r:Array = select("id", "gender", "age", "race", "income").eval(data);			
			trace(resultToString(r));
			*/
		}
		
		private function resultToArray(r:Array, group:String):Array
		{
			var arr:Array = new Array();
			for each (var obj:Object in r) {
				arr.push({name:obj[group], value:obj.count});
			}
			return arr;
		}
		
		private function resultToString(r:Array):String
		{
			var s:String = "";
			for each (var obj:Object in r) {
				for each (var el:Object in obj) {
					s += el + '\t';
				}
				s += '\n';
			}
			return s;
		}

	}
}
